package org.dftproject.gedcom.core;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Line {

	private static final Pattern linePattern = Pattern.compile("\\s*(0|[1-9][0-9]*)\\s+(?:@([^@]+)@\\s+)?([^\\s]+)(?:\\s+@([^@]+)@)?(?:\\s+(.*))?");

	private Line parent;
	private short level = 0;
	private final String id;
	private final String tag;
	private final String pointer;
	private final String value;
	private final LinkedList<Line> lines = new LinkedList<Line>();

	public Line(String line) {
		Matcher matcher = linePattern.matcher(line);
		if (!matcher.matches())
			throw new IllegalArgumentException();
		
		try {
			level = Short.parseShort(matcher.group(1));
		} catch (NumberFormatException e) {
			throw new IllegalArgumentException();
		}
		
		id = matcher.group(2);
		tag = matcher.group(3);
		pointer = matcher.group(4);
		value = matcher.group(5);
	}

	public void addLine(Line line) {
		line.setParent(this);
		lines.add(line);
	}

	public Line getParent() {
		return parent;
	}

	protected void setParent(Line parent) {
		this.parent = parent;
	}

	public short getLevel() {
		return level;
	}

	public String getId() {
		return id;
	}

	public String getTag() {
		return tag;
	}

	public String getPointer() {
		return pointer;
	}

	public String getValue() {
		return value;
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append(level);
		sb.append(" ");
		if (id != null) {
			sb.append("@");
			sb.append(id);
			sb.append("@ ");
		}
		sb.append(tag);
		if (pointer != null) {
			sb.append(" @");
			sb.append(pointer);
			sb.append("@");
		}
		if (value != null) {
			sb.append(" ");
			sb.append(value);
		}
		
		return sb.toString();
	}
	
	public String toString(boolean recursive) {
		StringBuilder sb = new StringBuilder();
		sb.append(toString());
		if (recursive) {
			for (Line line : lines)
				sb.append("\n").append(line.toString(recursive));
		}
		return sb.toString();
	}

	public List<Line> getChildren() {
		return Collections.unmodifiableList(lines);
	}

	public List<Line> getChildren(String tag) {
		List<Line> results = new LinkedList<Line>();
		
		for (Line line : lines) {
			if (tag.equals(line.getTag()))
				results.add(line);
		}
		
		return Collections.unmodifiableList(results);
	}
	
	public List<Line> getChildren(String[] tags) {
		List<Line> results = new LinkedList<Line>();
		
		for (Line line : lines) {
			for (String tag : tags) {
				if (tag.equals(line.getTag())) {
					results.add(line);
					break;
				}
			}
		}
		
		return Collections.unmodifiableList(results);
	}
	
	public Line getChild(String tag) {
		for (Line line : lines) {
			if (tag.equals(line.getTag()))
				return line;
		}
		
		return null;
	}

	public String getTabbedString() {
		StringBuilder sb = new StringBuilder();
		for (short i = 0; i < level; i++)
			sb.append("\t");
		if (id != null) {
			sb.append("@");
			sb.append(id);
			sb.append("@ ");
		}
		sb.append(tag);
		if (pointer != null) {
			sb.append(" @");
			sb.append(pointer);
			sb.append("@");
		}
		if (value != null) {
			sb.append(" ");
			sb.append(value);
		}
		
		return sb.toString();
	}

}
